﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EnvDTE;
using EnvDTE80;
using System.Text.RegularExpressions;

namespace BovespaUsageRules
{
    public sealed class Rule_BovespaDoNotOperateLoopControl : BaseAddIn.Rules.BaseRuleAddIn
    {
        #region Constant

        const string REGULAR_EXPRESSION_INSTRUCTION_FOR = @"for((\s+)\(|(\n+)\(|\()";

        #endregion

        #region Constructor

        public Rule_BovespaDoNotOperateLoopControl() :
            base("BovespaDoNotOperateLoopControl", "BovespaUsageRules.BovespaUsageRules", typeof(Rule_BovespaDoNotOperateLoopControl).Assembly)
        {
        }

        #endregion

        #region Protected Override Methods

        protected sealed override void Check(CodeFunction funcao, CodeNamespace namespaceElement, CodeClass2 classe)
        {
            CodeElement elemento = funcao as CodeElement;

            EditPoint edit = elemento.StartPoint.CreateEditPoint();
            string bodyMethod = edit.GetText((funcao as CodeElement).EndPoint);

            int indexSimbolFor = 0;
            string variableName = string.Empty;
            string blockFor = string.Empty;


            if (!classe.StartPoint.Parent.Parent.FullName.Contains(".Designer."))
            {
                bodyMethod = this.FormatBodyMethod(bodyMethod);

                Regex regLoopFor = new Regex(REGULAR_EXPRESSION_INSTRUCTION_FOR, RegexOptions.Multiline);

                foreach (Match match in regLoopFor.Matches(bodyMethod))
                {
                    indexSimbolFor = 0;
                    variableName = this.GetVariableName(match.Value, bodyMethod, out indexSimbolFor);

                    if (!string.IsNullOrEmpty(variableName))
                    {
                        blockFor = this.GetBlockFor(indexSimbolFor, bodyMethod);

                        variableName = string.Concat(" ", variableName.Trim(), " ");

                        if (!string.IsNullOrEmpty(blockFor) && blockFor.Contains(variableName))
                            GeraProblemaAddIn(classe.StartPoint.Parent.Parent.FullName,
                                             elemento.StartPoint.Line,
                                             elemento.StartPoint.DisplayColumn,
                                             "BovespaDoNotOperateLoopControlResolution",
                                             classe.Name,
                                             elemento.Name,
                                             namespaceElement.Name);
                    }
                }
            }
        }

        #endregion

        #region Private Methods

        private String GetBlockFor(int indexSimbolFor, string bodyMethod)
        {
            string beginingFor = string.Empty;
            string blockFor = string.Empty;

            string currentChar = string.Empty;
            List<String> listBeginEndBlocks = new List<String>();

            while (indexSimbolFor <= bodyMethod.Length && !this.CheckClosedBlock(listBeginEndBlocks))
            {
                currentChar = bodyMethod.Substring(indexSimbolFor, 1);

                if (currentChar == "{" || currentChar == "}")
                    listBeginEndBlocks.Add(currentChar);

                if (listBeginEndBlocks.Count > 0)
                    blockFor += currentChar;

                indexSimbolFor++;
            }

            return blockFor;
        }

        private String GetVariableName(string forFound, string bodyMethod, out int indexSimbolFor)
        {
            string variable = string.Empty;
            string txtContainsVariable = string.Empty;
            string[] str = new string[] { "\\s", "=", ";", "-", "+", "(", " ", "?" };

            indexSimbolFor = 0;

            if (!forFound.Trim().Equals(""))
            {
                indexSimbolFor = bodyMethod.IndexOf(forFound) + forFound.Length - 1;

                while (!txtContainsVariable.Contains(";") && indexSimbolFor <= bodyMethod.Length)
                {
                    txtContainsVariable += bodyMethod.Substring(indexSimbolFor, 1);
                    indexSimbolFor++;
                }

                if (!txtContainsVariable.Trim().Equals(""))
                {
                    List<String> listStr = txtContainsVariable.Split('=').ToList()[0].Split(str, StringSplitOptions.RemoveEmptyEntries).ToList<String>();

                    switch (listStr.Count)
                    {
                        case 1:
                            variable = listStr[0];
                            break;
                        case 2:
                            variable = listStr[1];
                            break;
                        default:
                            variable = string.Empty;
                            break;
                    }

                }
            }

            return variable;
        }

        private String FormatBodyMethod(string bodyMethod)
        {
            bodyMethod = bodyMethod.Replace(Environment.NewLine, " ");
            bodyMethod = bodyMethod.Replace("=", " = ");
            bodyMethod = bodyMethod.Replace(";", " ; ");
            bodyMethod = bodyMethod.Replace(".", " . ");
            bodyMethod = bodyMethod.Replace("(", " ( ");
            bodyMethod = bodyMethod.Replace(")", " ) ");
            bodyMethod = bodyMethod.Replace("{", " { ");
            bodyMethod = bodyMethod.Replace("}", " } ");
            bodyMethod = bodyMethod.Replace("[", " [ ");
            bodyMethod = bodyMethod.Replace("]", " ] ");
            bodyMethod = bodyMethod.Replace("+", " + ");
            bodyMethod = bodyMethod.Replace("-", " - ");
            bodyMethod = bodyMethod.Replace("*", " * ");
            bodyMethod = bodyMethod.Replace("//", " // ");
            bodyMethod = bodyMethod.Replace("\\", " \\ ");
            bodyMethod = bodyMethod.Replace("?", " ? ");
            bodyMethod = bodyMethod.Replace("<", " < ");
            bodyMethod = bodyMethod.Replace(">", " > ");

            return bodyMethod;
        }

        private bool CheckClosedBlock(List<String> listChar)
        {
            if (listChar.Count == 0)
                return false;

            int numberBegin = listChar.Count<String>(c => c == "{");
            int numberEnd = listChar.Count<String>(c => c == "}");

            if (numberBegin == numberEnd)
                return true;
            else
                return false;
        }

        #endregion
    }
}
